import { Fetch } from './fetch'
import { Tool } from './tool'
import { Cache } from './cache'

export class Request {
    constructor({url, params = {}, data = {}, method = 'get', allowRepeatRequest = false,extraData = {},}) {
        this.target = Request.default.baseUrl + url
        this.extraData = extraData
        this.timeout = 0
        this.method = method
        this.headers = {}
        let config = {
            body: data,
            method,
            headers: Request.default.headers || {
                'Content-Type': 'application/json;charset=UTF-8'
            },
            timeout: Request.default.timeout,
            target: Request.default.baseUrl + url,
            urlParams: params
        }
        this.data = data
        this.params = params
        this.StatusCode = '0'
        this.allowRepeatRequest = allowRepeatRequest
        Object.defineProperty(config, 'request', {
            value: this,
            enumerable: false,
            configurable: false,
        })
        setTimeout(() => console.log(this))
        return new Promise(async (resolve, reject) => {
            this.setHiddenProperty('resolve', resolve)
            this.setHiddenProperty('reject', reject)
            this.mergeDefaultToConfig(config)
            try {
                if (Request.Intercepter.request.cepter) await Request.Intercepter.request.cepter.then(config);
                this.mergeConfig(config)
                this.repeat = new Cache(method === 'post' ? data : params, this.timeout)
                if (!this.allowRepeatRequest && this.testRepeat()) {
                    return reject(Tool.repeatTipMessage)
                }
            } catch(e) {
                return reject(e)
            }
            config.target = this.urlEncodeParams()
            config.body = JSON.stringify(config.body)
            Fetch.request(config)
                .then((e) => this.parseResultToJson(e))
                .then((e) => this.setResult(e))
                .catch((e) => this.setError(e))
        })
    }
}

Request.prototype.setHiddenProperty = function setHiddenProperty(name, value) {
    Object.defineProperty(this, name, {
        value,
        enumerable: false,
        configurable: false,
    })
}
Request.prototype.urlEncodeParams = function urlEncodeParams() {
    return this.target + Tool.objectUrlEncode(this.params)
}
Request.prototype.mergeConfig = function mergeConfig(config) {
    this.data = config.body
    this.params = config.urlParams
    this.headers = config.headers
    this.timeout = config.timeout
    return config
}
Request.prototype.setResult = async function setResult(data) {
    try{
        if (Request.Intercepter.response.cepter.then) this.result =  await Request.Intercepter.response.cepter.then(data, this.extraData);
        this.resolve(this.result)
        this.setRequestIsSuccess(true)
        this.onComplete()
    } catch (e){
        return this.setError(e)
    }
}
Request.prototype.setError = async function setError(err) {
    try {
        if (Request.Intercepter.response.cepter.error) {
            this.result = await Request.Intercepter.response.cepter.error(err, this.extraData);
            this.resolve(this.result)
            this.setRequestIsSuccess(true)
        } else {
            this.result = err
            this.reject(this.result)
            console.error('请求错误:'+this.target, this)
            this.setRequestIsSuccess(false)
            this.onComplete()
        }
    }catch(e){
        this.result = e
        this.reject(e)
        console.error('请求错误:'+this.target, this)
        this.setRequestIsSuccess(false)
        this.onComplete()
    }
}

Request.prototype.setRequestIsSuccess = function setRequestIsSuccess(type) {
    this.requestIsSuccess = type
}
Request.prototype.onComplete = function onComplete() {
    this.repeat.clear()
}
Request.prototype.setDefault = function setDefault(option) {
    Request.default = option
}
Request.prototype.testRepeat = function testRepeat() {
    if (this.repeat.isRepeat()) {
        if (Request.Intercepter.repeatTip.cepter) Request.Intercepter.repeatTip.cepter();
        return true
    }
}
Request.prototype.parseResultToJson = function parseResultToJson(r) {
    this.StatusCode = r.status
    if (r.status == 200) {
        return r.json()
    } else {
        return Promise.reject(r)
    }
}
Request.prototype.mergeDefaultToConfig = function mergeDefaultToConfig(config) {
    let defaultOption = Request.default
    if (!defaultOption) return;
    if (defaultOption.method) config.method = defaultOption.method;
    if (defaultOption.timeout) config.timeout = defaultOption.timeout;
    if (defaultOption.baseUrl) config.baseUrl = defaultOption.baseUrl;
    Tool.clone(defaultOption,'data', config)
    Tool.clone(defaultOption,'params', config)
    Tool.clone(defaultOption,'headers', config)
}

Request.Intercepter = {
    request: {
        cepter: {},
        use(then) {
            this.cepter = { then }
            return this.cepter
        }
    },
    response: {
        cepter: {},
        use(then, error) {
            this.cepter = { then, error }
            return this.cepter
        },
    },
    repeatTip: {
        cepter: null,
        use(cepter) {
            this.cepter = cepter
        }
    }
}

Request.default = {}

export default Request;